home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 8: LINUX Games
/
Linux Cubed Series 8 - LINUX Games.iso
/
games
/
x11
/
rpg
/
crossfir.92
/
crossfir
/
crossfire-0.92.5
/
server
/
time.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-24
|
21KB
|
790 lines
/*
* static char *rcsid_time_c =
* "$Id: time.c,v 1.30 1996/01/02 11:53:56 master Exp $";
*/
/*
CrossFire, A Multiplayer game for X-windows
Copyright (C) 1994 Mark Wedel
Copyright (C) 1992 Frank Tore Johansen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The author can be reached via e-mail to master@rahul.net
*/
/*
* Routines that is executed from objects based on their speed have been
* collected in this file.
*/
#include <global.h>
#include <spells.h>
#ifndef __CEXTRACT__
#include <sproto.h>
#endif
/* The following removes doors. The functions check to see if similar
* doors are next to the one that is being removed, and if so, set it
* so those will be removed shortly (in a cascade like fashion.)
*/
void remove_door(object *op) {
int i;
object *tmp;
for(i=1;i<9;i+=2)
if((tmp=present(DOOR,op->map,op->x+freearr_x[i],op->y+freearr_y[i]))!=NULL) {
tmp->speed = 0.1;
update_ob_speed(tmp);
tmp->speed_left= -0.2;
}
remove_ob(op);
free_object(op);
}
void remove_door2(object *op) {
int i;
object *tmp;
for(i=1;i<9;i+=2) {
tmp=present(LOCKED_DOOR,op->map,op->x+freearr_x[i],op->y+freearr_y[i]);
if(tmp && tmp->slaying == op->slaying) {/* same key both doors */
tmp->speed = 0.1;
update_ob_speed(tmp);
tmp->speed_left= -0.2;
}
}
remove_ob(op);
free_object(op);
}
void generate_monster(object *gen) {
int i;
object *op,*head=NULL,*prev=NULL;
archetype *at=gen->other_arch;
if(GENERATE_SPEED(gen)&&RANDOM()%GENERATE_SPEED(gen))
return;
if(gen->other_arch==NULL) {
LOG(llevError,"Generator without other_arch: %s\n",gen->name);
return;
}
i=find_free_spot(at,gen->map,gen->x,gen->y,1,9);
if(!i) return;
while(at!=NULL) {
op=arch_to_object(at);
op->x=gen->x+freearr_x[i]+at->clone.x;
op->y=gen->y+freearr_y[i]+at->clone.y;
if(head!=NULL)
op->head=head,prev->more=op;
insert_ob_in_map(op,gen->map);
if (QUERY_FLAG(op, FLAG_FREED)) return;
if(op->arch->randomitems!=NULL)
create_treasure(op->arch->randomitems,op,GT_INVENTORY,
gen->map->difficulty,0);
if(head==NULL)
head=op;
prev=op;
at=at->more;
}
if(gen->stats.food&&!--(gen->stats.food)) {
remove_ob(gen);
free_object(gen);
}
}
void regenerate_rod(object *rod) {
if(++rod->stats.food > rod->stats.hp/10 || rod->type == HORN) {
rod->stats.food = 0;
if (rod->stats.hp < rod->stats.maxhp) {
rod->stats.hp += 1 + rod->stats.maxhp/10;
if (rod->stats.hp > rod->stats.maxhp)
rod->stats.hp = rod->stats.maxhp;
fix_rod_speed(rod);
}
}
}
void remove_force(object *op) {
if(op->env==NULL) {
remove_ob(op);
free_object(op);
return;
}
CLEAR_FLAG(op, FLAG_APPLIED);
change_abil(op->env,op);
fix_player(op->env);
remove_ob(op);
free_object(op);
}
void remove_blindness(object *op) {
if(--op->stats.food > 0)
return;
CLEAR_FLAG(op, FLAG_APPLIED);
if(op->env!=NULL) {
change_abil(op->env,op);
fix_player(op->env);
}
remove_ob(op);
free_object(op);
}
void remove_confusion(object *op) {
if(--op->stats.food > 0)
return;
if(op->env!=NULL) {
CLEAR_FLAG(op->env, FLAG_CONFUSED);
new_draw_info(NDI_UNIQUE, 0,op->env, "You regain your senses.\n");
}
remove_ob(op);
free_object(op);
}
void execute_wor(object *op) {
object *wor=op;
while(op!=NULL&&op->type!=PLAYER)
op=op->env;
if(op!=NULL) {
if(blocks_magic(op->map,op->x,op->y))
new_draw_info(NDI_UNIQUE, 0,op,"You feel something fizzle inside you.");
else
enter_exit(op,wor);
}
remove_ob(wor);
free_object(wor);
}
void poison_more(object *op) {
if(op->env==NULL||!QUERY_FLAG(op->env,FLAG_ALIVE)||op->env->stats.hp<0) {
remove_ob(op);
free_object(op);
return;
}
if(op->stats.food==1) {
/* need to remove the object before fix_player is called, else fix_player
* will not do anything.
*/
if(op->env->type==PLAYER) {
CLEAR_FLAG(op, FLAG_APPLIED);
fix_player(op->env);
new_draw_info(NDI_UNIQUE, 0,op->env,"You feel much better now.");
}
remove_ob(op);
free_object(op);
return;
}
if(op->env->type==PLAYER) {
op->env->stats.food--;
new_draw_info(NDI_UNIQUE, 0,op->env,"You feel very sick...");
draw_stats(op->env);
}
(void)hit_player(op->env,
op->stats.dam,
op,AT_PHYSICAL);
}
void move_gate(object *op) { /* 1 = going down, 0 = goind up */
object *tmp;
if(op->stats.wc < 0 || (int)op->stats.wc > (int)op->arch->animations-1) {
LOG(llevError,"Gate error: animation was %d\n",op->stats.wc);
dump_object(op);
LOG(llevError,"%s\n",errmsg);
op->stats.wc=0;
}
if(op->value) { /* We're going down */
if(--op->stats.wc<=0) { /* Reached bottom, let's stop */
op->stats.wc=0;
if(op->arch->clone.speed)
op->value=0;
else {
op->speed = 0;
update_ob_speed(op);
}
CLEAR_FLAG(op, FLAG_NO_PASS);
CLEAR_FLAG(op, FLAG_BLOCKSVIEW);
update_all_los(op->map);
}
if((int)op->stats.wc <= ((int)op->arch->animations-1)/2+1) {
CLEAR_FLAG(op, FLAG_NO_PASS);
CLEAR_FLAG(op, FLAG_BLOCKSVIEW);
update_all_los(op->map);
}
op->face=&new_faces[op->arch->faces[op->stats.wc]];
update_object(op);
return;
}
/* We're going up */
if((unsigned char) op->stats.wc==(op->arch->animations-1)&&op->above==NULL) {
if(op->arch->clone.speed)
op->value=1;
else {
op->speed = 0;
update_ob_speed(op); /* Reached top, let's stop */
}
return;
}
if(op->stats.food) { /* The gate is going temporarily down */
if(--op->stats.wc<=0) /* Gone all the way down? */
op->stats.food=0, /* Then let's try again */
op->stats.wc=0;
} else { /* The gate is still going up */
op->stats.wc++;
if((int)op->stats.wc > ((int)op->arch->animations-1))
op->stats.wc=(signed char)op->arch->animations-1;
if((int)op->stats.wc >= (int)op->arch->animations/2) {
/* Halfway or further, check blocks */
for(tmp=op->above;tmp!=NULL&&tmp->above!=NULL;tmp=tmp->above); /* top */
if(tmp!=NULL) {
if(QUERY_FLAG(tmp, FLAG_ALIVE)) {
hit_player(tmp,RANDOM()%(op->stats.dam+1)+1,op,AT_PHYSICAL);
if(tmp->type==PLAYER) {
new_draw_info_format(NDI_UNIQUE, 0, tmp,
"You are crushed by the %s!",op->name);
}
} else if(!(tmp->speed&&tmp->direction)) {
/* If it has speed, it should move itself, otherwise: */
int i=find_free_spot(tmp->arch,op->map,op->x,op->y,1,9);
remove_ob(tmp);
tmp->x+=freearr_x[i],tmp->y+=freearr_y[i];
insert_ob_in_map(tmp,op->map);
}
}
if(op->above!=NULL) /* Still something in the way? */
op->stats.food=1; /* Then let's go down and gather some speed 8) */
else {
SET_FLAG(op, FLAG_NO_PASS); /* The coast is clear, block the way */
if(!op->arch->clone.stats.ac)
SET_FLAG(op, FLAG_BLOCKSVIEW);
update_all_los(op->map);
}
}
}
op->face=&new_faces[op->arch->faces[(unsigned char)op->stats.wc]];
update_object(op);
}
/* hp : how long door is open/closed
* maxhp : initial value for hp
* sp : 1 = open, 0 = close
*/
void move_timed_gate(object *op)
{
int v = op->value;
if (op->stats.sp) {
move_gate(op);
if (op->value != v) /* change direction ? */
op->stats.sp = 0;
return;
}
if (--op->stats.hp <= 0) { /* keep gate down */
move_gate(op);
if (op->value != v) { /* ready ? */
op->speed = 0;
update_ob_speed(op);
}
}
}
void animate_trigger (object *op)
{
if((unsigned char)++op->stats.wc >= op->arch->animations-1) {
op->stats.wc = 0;
check_trigger(op);
}
op->face=&new_faces[op->arch->faces[op->stats.wc]];
update_object(op);
}
void move_hole(object *op) { /* 1 = opening, 0 = closing */
if(op->value) { /* We're opening */
if(--op->stats.wc<=0) { /* Opened, let's stop */
op->stats.wc=0;
op->speed = 0;
update_ob_speed(op);
SET_FLAG(op, FLAG_WALK_ON);
while(op->above!=NULL && apply(op->above,op))
;
}
op->face=&new_faces[op->arch->faces[op->stats.wc]];
update_object(op);
return;
}
/* We're closing */
CLEAR_FLAG(op, FLAG_WALK_ON);
op->stats.wc++;
if((int)op->stats.wc > (int)op->arch->animations-1)
op->stats.wc=op->arch->animations-1;
op->face=&new_faces[op->arch->faces[op->stats.wc]];
update_object(op);
if((unsigned char) op->stats.wc==op->arch->animations-1) {
op->speed = 0;
update_ob_speed(op); /* closed, let's stop */
return;
}
}
void stop_arrow(object *op,object *tmp) {
if(wall(op->map,op->x,op->y))
op->x-=DIRX(op),op->y-=DIRY(op);
if(wall(op->map, op->x, op->y))
{
free_object(op);
return;
}
if(RANDOM() % 100 < op->stats.food) {
/* Small chance of breaking */
free_object(op);
return;
}
op->direction=0;
CLEAR_FLAG(op, FLAG_WALK_ON);
CLEAR_FLAG(op, FLAG_FLY_ON);
CLEAR_FLAG(op, FLAG_FLYING);
op->speed = 0;
update_ob_speed(op);
op->stats.wc = op->stats.sp;
op->stats.dam= op->stats.hp;
/* Reset these to zero, so that CAN_MERGE will work properly */
op->stats.sp = 0;
op->stats.hp = 0;
op->face=op->arch->clone.face;
if(tmp!=NULL&&tmp->stats.hp>=0) {
if(tmp->head != NULL)
tmp = tmp->head;
op = insert_ob_in_ob(op,tmp);
if (tmp->type== PLAYER && tmp->contr->eric_server > 0)
esrv_send_item (tmp, op);
} else
insert_ob_in_map(op,op->map);
op->owner=NULL; /* So that stopped arrows will be saved */
}
void move_arrow(object *op) {
object *tmp;
if(op->map==NULL) {
LOG(llevError,"Arrow had no map.\n");
remove_ob(op);
free_object(op);
return;
}
remove_ob(op);
if(wall(op->map,op->x+DIRX(op),op->y+DIRY(op)))
if(!QUERY_FLAG(op, FLAG_REFLECTING) || !(RANDOM()%20)) {
stop_arrow(op,NULL);
return;
} else {
if(op->direction&1)
op->direction=absdir(op->direction+4);
else {
int left= wall(op->map,op->x+freearr_x[absdir(op->direction-1)],
op->y+freearr_y[absdir(op->direction-1)]),
right=wall(op->map,op->x+freearr_x[absdir(op->direction+1)],
op->y+freearr_y[absdir(op->direction+1)]);
if(left==right)
op->direction=absdir(op->direction+4);
else if(left)
op->direction=absdir(op->direction+2);
else if(right)
op->direction=absdir(op->direction-2);
}
if(wall(op->map,op->x+DIRX(op),op->y+DIRY(op)))
{
int left= wall(op->map,op->x+freearr_x[absdir(op->direction-1)],
op->y+freearr_y[absdir(op->direction-1)]),
right=wall(op->map,op->x+freearr_x[absdir(op->direction+1)],
op->y+freearr_y[absdir(op->direction+1)]);
if(!left)
op->direction=absdir(op->direction-1);
else if(!right)
op->direction=absdir(op->direction+1);
else { /* is this possible? */
stop_arrow(op,NULL);
return;
}
}
op->face=&new_faces[op->arch->faces[op->direction]];
}
op->x+=DIRX(op),op->y+=DIRY(op);
tmp=get_map_ob(op->map,op->x,op->y);
while(tmp!=NULL&&!QUERY_FLAG(tmp, FLAG_ALIVE))
tmp=tmp->above;
if(tmp==NULL) {
insert_ob_in_map(op,op->map);
return;
}
if (QUERY_FLAG(tmp, FLAG_REFL_MISSILE)){
int number = op->face->number;
op->direction=absdir(op->direction+4),op->state=0;
number+=4;
if(number > op->arch->faces[8])
number-=8;
op->face = &new_faces[number];
insert_ob_in_map(op,op->map);
return;
}
if(attack_ob(tmp,op))
stop_arrow(op,tmp);
else
if(op->direction)
insert_ob_in_map(op,op->map);
else
stop_arrow(op,NULL);
}
#if 0
void stop_thrown(object *op,object *tmp) {
if(wall(op->map,op->x,op->y))
op->x-=DIRX(op),op->y-=DIRY(op);
op->direction=0;
UNSET_FLY(op);
if(op->type!=BOMB) {
update_ob_speed(op,0);
op->speed_left= -2;
}
insert_ob_in_map(op,op->map);
if(tmp!=NULL&&tmp->stats.hp>=0) { /* Hack to get monster on top */
remove_ob(tmp);
insert_ob_in_map(tmp,tmp->map);
}
}
#endif
#if 0 /* This routine is buggy, and removed for now */
void move_thrown(object *op) {
object *tmp;
int roll;
char buf[MAX_BUF];
remove_ob(op);
if(op->thrown--<1) {
stop_thrown(op,NULL);
return;
}
op->x+=DIRX(op),op->y+=DIRY(op);
if(out_of_map(op->map,op->x,op->y)) {
LOG(llevError,"Thrown object out of map.\n");
stop_thrown(op,NULL);
remove_ob(op);
free_object(op);
return;
}
if(wall(op->map,op->x,op->y)) {
stop_thrown(op,NULL);
return;
}
tmp=get_map_ob(op->map,op->x,op->y);
while(tmp!=NULL&&!QUERY_FLAG(tmp, FLAG_ALIVE))
tmp=tmp->above;
if(tmp==NULL) {
insert_ob_in_map(op,op->map);
return;
}
roll=RANDOM()%20+1;
if(roll==20||tmp->stats.ac>=op->thrownthaco-roll) {
sprintf(buf,"%s hits you with %s.",op->owner->name,op->name);
new_draw_info(NDI_UNIQUE, 0,tmp,buf);
new_draw_info_format(NDI_ALL, 10, NULL,
"%s hits %s with %s.",op->owner->name,tmp->name,op->name);
hit_player(tmp,RANDOM()%(op->weight>50000?11:op->weight/5000+1),op->owner,
AT_PHYSICAL);
stop_thrown(op,tmp);
return;
} else
if(op->thrownthaco-roll<5) {
new_draw_info_format(NDI_ALL, 10, NULL,
"%s's %s hits %s's armour.",op->owner->name,op->name,tmp->name);
stop_thrown(op,tmp);
return;
}
insert_ob_in_map(op,op->map);
}
#endif
/* This routine doesnt seem to work for "inanimate" objects that
* are being carried, ie a held torch leaps from your hands!.
* Modified this routine to allow held objects. b.t. */
void change_object(object *op) { /* Doesn`t handle linked objs yet */
object *tmp,*env;
int i,j;
if(op->other_arch==NULL) {
LOG(llevError,"Change object (%s) without other_arch error.\n", op->name);
return;
}
env=op->env;
remove_ob(op);
for(i=0;i<NROFNEWOBJS(op);i++) {
tmp=arch_to_object(op->other_arch);
tmp->stats.hp=op->stats.hp; /* The only variable it keeps. */
if(env) {
tmp->x=env->x,tmp->y=env->y;
insert_ob_in_ob(tmp,env);
} else {
j=find_first_free_spot(tmp->arch,op->map,op->x,op->y);
tmp->x=op->x+freearr_x[j],tmp->y=op->y+freearr_y[j];
insert_ob_in_map(tmp,op->map);
}
}
free_object(op);
}
void move_teleporter(object *op) {
if(op->above!=NULL) {
if(EXIT_PATH(op)) {
if(op->above->type==PLAYER)
enter_exit(op->above,op);
else
return;
}
else if(EXIT_X(op)||EXIT_Y(op))
{
if (out_of_map(op->map, EXIT_X(op), EXIT_Y(op)))
{
LOG(llevError, "Removed illegal teleporter.\n");
remove_ob(op);
free_object(op);
return;
}
transfer_ob(op->above,EXIT_X(op),EXIT_Y(op));
} else
teleport(op,TELEPORTER);
}
}
/* peterm: firewalls generalized to be able to shoot any type
of spell at all. the stats.dam field of a firewall object
contains it's spelltype. The direction of the wall is stored
in op->stats.sp. maxsp also has some meaning, i'm not sure what.
walls can have hp, so they can be torn down. */
void move_firewall(object *op) {
cast_spell(op,op,op->stats.sp?op->stats.sp:(RANDOM()%8)+1,op->stats.dam,
1,spellNormal,NULL);
}
void move_firechest(object *op) {
fire_a_ball(op,(RANDOM()%8)+1,7);
}
/* move_player_mover: this function takes a "player mover" as an
argument, and performs the function of a player mover, which is:
a player mover finds any players that are sitting on it. It
moves them in the op->stats.sp direction. speed is how often it'll move.
If attacktype is nonzero it will paralyze the player. If lifesave is set,
it'll dissapear after hp+1 moves. If hp is set and attacktype is set,
it'll paralyze the victim for hp*his speed/op->speed
*/
void move_player_mover(object *op) {
object *victim, *nextmover;
for(victim=get_map_ob(op->map,op->x,op->y); victim !=NULL; victim=victim->above)
if(QUERY_FLAG(victim, FLAG_ALIVE)&& (!(QUERY_FLAG(victim,FLAG_FLYING))||op->stats.maxhp))
{
if(QUERY_FLAG(op,FLAG_LIFESAVE)&&op->stats.hp--<0) {
remove_ob(op);
free_object(op);
return;
}
for(nextmover=get_map_ob(op->map,op->x+freearr_x[op->stats.sp],op->y+freearr_y[op->stats.sp]); nextmover !=NULL; nextmover=nextmover->above) {
if(nextmover->type == PLAYERMOVER)
{ nextmover->speed_left=-.99;}
if(QUERY_FLAG(nextmover,FLAG_ALIVE)) {
op->speed_left=-1.1; /* wait until the next thing gets out of the way */
}
}
if(victim->type==PLAYER) /* only level >=1 movers move people */
{ if(op->level) move_player(victim, op->stats.sp?op->stats.sp:(RANDOM()%8)+1);
else return;
}
else move_object(victim,op->stats.sp?op->stats.sp:(RANDOM()%8)+1);
if(!op->stats.maxsp&&op->attacktype) op->stats.maxsp=2.0;
if(op->attacktype) /* flag to paralyze the player */
victim->speed_left= -FABS(op->stats.maxsp*victim->speed/op->speed);
}
}
/* move_creator (by peterm)
it has the creator object create it's other_arch right on top of it.
connected: what will trigger it
hp: how many times it may create before stopping
lifesave: if set, it'll never disappear but will go on creating
everytime it's triggered
other_arch: the object to create
*/
void move_creator(object *op) {
object *tmp;
op->stats.hp--;
if(op->stats.hp < 0 && !QUERY_FLAG(op,FLAG_LIFESAVE))
{ op->stats.hp=-1;return;}
tmp=arch_to_object(op->other_arch);
tmp->x=op->x;tmp->y=op->y;tmp->map=op->map;tmp->level=op->level;
insert_ob_in_map(tmp,op->map);
}
int process_object(object *op) {
if(QUERY_FLAG(op, FLAG_MONSTER))
if(move_monster(op) || QUERY_FLAG(op, FLAG_FREED))
return 1;
if(QUERY_FLAG(op, FLAG_ANIMATE) && op->anim_speed==0) {
animate_object(op);
if (QUERY_FLAG(op, FLAG_SEE_ANYWHERE))
make_sure_seen(op);
}
if(QUERY_FLAG(op, FLAG_CHANGING)&&!op->state) {
change_object(op);
return 1;
}
if(QUERY_FLAG(op, FLAG_GENERATOR))
generate_monster(op);
if(QUERY_FLAG(op, FLAG_IS_USED_UP)&&--op->stats.food<=0) {
if(QUERY_FLAG(op, FLAG_APPLIED))
remove_force(op);
else {
remove_ob(op);
if (QUERY_FLAG(op, FLAG_SEE_ANYWHERE))
make_sure_not_seen(op);
free_object(op);
}
return 1;
}
switch(op->type) {
case ROD:
case HORN:
regenerate_rod(op);
return 1;
case FORCE:
remove_force(op);
return 1;
case BLINDNESS:
remove_blindness(op);
return 0;
case CONFUSION:
remove_confusion(op);
return 0;
case POISONING:
poison_more(op);
return 0;
case WORD_OF_RECALL:
execute_wor(op);
return 0;
case BULLET:
move_fired_arch(op);
return 0;
case MMISSILE:
move_missile(op);
return 0;
case ARROW:
move_arrow(op);
return 0;
case FBULLET:
move_fired_arch(op);
return 0;
case FBALL:
case POISONCLOUD:
explosion(op);
return 0;
case LIGHTNING: /* It now moves twice as fast */
move_bolt(op);
return 0;
case CONE:
move_cone(op);
return 0;
case DOOR:
remove_door(op);
return 0;
case LOCKED_DOOR:
remove_door2(op);
return 0;
case TELEPORTER:
move_teleporter(op);
return 0;
case BOMB:
animate_bomb(op);
return 0;
case GOLEM:
move_golem(op);
return 0;
case EARTHWALL:
hit_player(op, 2, op, AT_PHYSICAL);
return 0;
case FIREWALL:
move_firewall(op);
if (op->stats.maxsp)
animate_turning(op);
return 0;
case FIRECHEST:
move_firechest(op);
return 0;
case MOOD_FLOOR:
do_mood_floor(op, op);
return 0;
case GATE:
move_gate(op);
return 0;
case TIMED_GATE:
move_timed_gate(op);
return 0;
case TRIGGER:
case TRIGGER_BUTTON:
case TRIGGER_PEDESTAL:
case TRIGGER_ALTAR:
animate_trigger(op);
return 0;
case DIRECTOR:
if (op->stats.maxsp)
animate_turning(op);
return 0;
case HOLE:
move_hole(op);
return 0;
case DEEP_SWAMP:
deep_swamp(op, 0);
return 0;
case CANCELLATION:
move_cancellation(op);
return 0;
case BALL_LIGHTNING:
move_ball_lightning(op);
return 0;
case SWARM_SPELL:
move_swarm_spell(op);
return 0;
case RUNE:
move_rune(op);
return 0;
case PLAYERMOVER:
move_player_mover(op);
return 0;
}
return 0;
}